#include "Framebuffer.h"
#include "tcp_server.h"
#include "v4l2.h"

struct Info
{
    VideoDevice *ptVideoDevice;
    Framebuffer *ptFramebuffer;
    Tcp_server  *ptTcp_server;
};

volatile sig_atomic_t flags = 0;

void sighandler(int arg)
{
    if(arg == SIGINT)
    {
        flags = 1;
    }
}

void* pthread_handler(void* arg)
{   
    pthread_detach(pthread_self());
    struct Info info = *((struct Info *)arg);
    info.ptVideoDevice->number = 0;
    
    while(1){
        if(info.ptVideoDevice->v4l2_dqbuf() == -1)
        {
            continue;
        }

        info.ptVideoDevice->v4l2_video_handle(); 
        
        /* 刷白屏 */
        // memset(info.ptFramebuffer->fbMapMem, 0xff, info.ptFramebuffer->screen_size);
        // info.ptFramebuffer->display_rgb_to_framebuffer(info.ptVideoDevice->rgb_data[info.ptVideoDevice->iVideoBufCurIndex], info.ptVideoDevice->iHeight, info.ptVideoDevice->iWidth);
        // info.ptFramebuffer->display_rgb_to_framebuffer(info.ptVideoDevice->resized_rgb_data[info.ptVideoDevice->iVideoBufCurIndex], info.ptFramebuffer->iHeight, info.ptFramebuffer->iWidth);

        info.ptTcp_server->send_rgb_data(info.ptVideoDevice);

        info.ptVideoDevice->v4l2_qbuf();
    }

    return NULL;
}

int main(int argc, char const *argv[])
{
    if(argc < 4)
    {
        ERROR("argc < 4 failed");
    }

    signal(SIGINT, sighandler);
    // signal(SIGPIPE, SIG_IGN);

    pthread_t thread;
    struct Info info;
    struct pollfd fds[1];

    VideoDevice *ptVideoDevice = nullptr;
    Framebuffer *ptFramebuffer = nullptr;
    Tcp_server  *ptTcp_server  = nullptr;

    try{
        ptVideoDevice = new VideoDevice();
        ptFramebuffer = new Framebuffer();
        ptTcp_server  = new Tcp_server();
    }catch(const std::bad_alloc& e){
        std::cerr << RED <<"Memory allocation failed: " << e.what() << END << std::endl;
    }

    ptVideoDevice->Init(argv);

    ptVideoDevice->v4l2_cap();

    ptVideoDevice->v4l2_input();
    
    ptVideoDevice->v4l2_fmt();

    ptVideoDevice->v4l2_reqbufs();

    ptVideoDevice->v4l2_streamon();

    // ptFramebuffer->Init();

    // ptFramebuffer->getFramebufferinfo();

    ptVideoDevice->new_rgb_data();
#if 1
    ptTcp_server->Init(argv);

    fds[0].fd = ptTcp_server->sockfd;
    fds[0].events = POLLIN;

    while(!flags)
    {   
        if(poll(fds, 1, 500) == -1)
        {
            if(errno == EINTR){
                continue;
            }
            Print_RED("poll is failed!");
            break;
        }
        
        if(fds[0].revents & POLLIN)
        {
            if(ptTcp_server->accept_wait_client() == -1)
            {
                continue;
            }

            memset(&info, 0, sizeof(info));
            info.ptVideoDevice = ptVideoDevice;
            info.ptFramebuffer = ptFramebuffer;
            info.ptTcp_server = ptTcp_server;

            pthread_create(&thread, NULL, pthread_handler, &info);
        }
    }
#else
            memset(&info, 0, sizeof(info));
            info.ptVideoDevice = ptVideoDevice;
            info.ptFramebuffer = ptFramebuffer;
            info.ptTcp_server = ptTcp_server;

            pthread_create(&thread, NULL, pthread_handler, &info);

            while(!flags)
            {
                sleep(1);
            }
#endif

    ptVideoDevice->v4l2_streamoff();
    ptFramebuffer->closeFramebuffer();
     
    delete ptVideoDevice;
    delete ptFramebuffer;
    delete ptTcp_server;
    return 0;
}
